﻿#include "EasyTcpServer.h"

#include "CELL.h"
#include "CELLTimestamp.hpp"
#include "CELLTask.hpp"
#include "INetEvent.h"
#include "CELLSelectServer.h"
#include "CELLClient.h"
#include "CELLNetWork.hpp"
#include "CELLConfig.hpp"

#include <stdio.h>
#include <string.h>
#include <vector>
#include <map>
#include <thread>
#include <mutex>
#include <atomic>
#include <algorithm>
#include <memory>
#include <iostream>

EasyTcpServer::EasyTcpServer() 
{
	_nMaxClient = CELLConfig::Instance().getNum("nMaxClient", 1000);
	_nSendBuffSize = CELLConfig::Instance().getNum("nSendBuffSize", 20480);
	_nRecvBuffSize = CELLConfig::Instance().getNum("nRecvBuffSize", 10240);
}

EasyTcpServer::~EasyTcpServer()
{
	Close();
}

// 初始化socket
SOCKET EasyTcpServer::InitSocket()
{
	CELLNetWork::Init();
	if (_sock != INVALID_SOCKET)
	{
		CELLLog_Warning("close old connect _sock : %d", _sock);
		Close();
	}
	
	_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (_sock == SOCKET_ERROR)
	{
		CELLLog_pError("create _sock error");
	}
	else
	{
		CELLNetWork::make_reuseaddr(_sock);
		CELLLog_Info("create _sock : %d successful", _sock);
	}
	return _sock;
}
// 绑定IP和端口
int EasyTcpServer::Bind(const char *ip, unsigned short port)
{
	if (_sock == INVALID_SOCKET)
	{
		InitSocket();
	}
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(port);
	if (ip)
	{
		sin.sin_addr.s_addr = inet_addr(ip);
	}
	else
	{
		sin.sin_addr.s_addr = htonl(INADDR_ANY);
	}

	int ret = ::bind(_sock, (struct sockaddr*) & sin, sizeof(sin));
	if (ret == SOCKET_ERROR)
	{
		CELLLog_pError("bind sock : %d error ", (int)_sock);
	}
	CELLLog_Info("bind sock : %d success ", (int)_sock);
	return ret;
}

// 监听端口
int EasyTcpServer::Listen(int backlog)
{
	if (_sock == INVALID_SOCKET)
	{
		return -1;
	}
	int ret = listen(_sock, backlog);
	if (ret == SOCKET_ERROR)
	{
		CELLLog_pError("listen sock : %d error", (int)_sock);
	}
	CELLLog_Info("listen sock : %d success", (int)_sock);
	return ret;
}

// 关闭socket
void EasyTcpServer::Close()
{
	CELLLog_Info("EasyTcpServer Close ===== begin");
	_thread.Close();
	if (_sock != INVALID_SOCKET)
	{
		for (auto s : _cellServers)
		{
			delete s;
		}
		_cellServers.clear();

		CELLNetWork::destorySocket(_sock);
		_sock = INVALID_SOCKET;
	}
	CELLLog_Info("EasyTcpServer Close ===== end");
}

// 接收客户端连接
SOCKET EasyTcpServer::Accept()
{
	if (_sock == SOCKET_ERROR)
	{
		return -1;
	}
	struct sockaddr_in client_addr;
	socklen_t client_len = sizeof(client_addr);
	SOCKET cSock = INVALID_SOCKET;
	cSock = accept(_sock, (struct sockaddr*) & client_addr, &client_len);
	if (cSock == INVALID_SOCKET)
	{
		CELLLog_pError("EasyTcpServer accept error on line %d", __LINE__);
	}
	else
	{
		if (_clientCount < _nMaxClient)
		{
			// 此处可以做登陆校验
			//CELLLog::Info("New Client IP: %s, PORT: %hu, sock: %d", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), (int)cSock);
			// 将新客户端分配给队列最小的一个服务线程去处理
			AddClientToCELLServer(new CELLClient(cSock, _nSendBuffSize, _nRecvBuffSize));
		}
		else
		{
			// 连接上限，可以给他发送一些消息或者做别的业务
			// 只要不是恶意攻击
			CELLNetWork::destorySocket(cSock);
			CELLLog_Warning("Accept to nMaxClient");
		}
	}
	return cSock;
}

void EasyTcpServer::AddClientToCELLServer(CELLClient* pClient)
{
	auto minServer = *(_cellServers.begin());
	for (std::vector<CELLServer*>::iterator it = _cellServers.begin(); it != _cellServers.end(); ++it)
	{
		// 选择一个存放客户端最少的CELLServer放进去
		if ((*it)->GetClientCount() < (*it)->GetClientCount())
		{
			minServer = *it;
		}
	}
	minServer->AddClient(pClient);
}

// 处理消息，响应网络消息
void EasyTcpServer::time4msg()
{
	auto t1 = _tTime.getElapsedSecond();
	if (t1 >= 1.0)
	{
		CELLLog_Info("thread_count<%d>, time<%lf>, sock<%d>, clients<%d>, recv<%d>, _msg<%d>", (int)_cellServers.size(), t1, _sock, (int)_clientCount, (int)(_recvCount), (int)(_recvMsg));
		_recvCount = 0;
		_recvMsg = 0;
		_tTime.update();
	}
}

SOCKET EasyTcpServer::sockfd()
{
	return _sock;
}

// 客户端加入事件，由主线程一个线程调用
void EasyTcpServer::OnNetJoin(CELLClient* pClient)
{
	++_clientCount;
	// CELLLog_Info("client<%d> join", pClient->sockfd());
}

// 客户端断开连接事件，由CELLServer多个线程调用 不安全
void EasyTcpServer::OnNetLeave(CELLClient* pClient)
{
	--_clientCount;
	// CELLLog_Info("client<%d> leave", pClient->sockfd());
}

// 客户端消息事件，由CELLServer多个线程调用 不安全
void EasyTcpServer::OnNetMsg(CELLServer* pCELLServer, CELLClient* pCLient, DataHeader* header)
{
	++_recvMsg;
}

void EasyTcpServer::OnNetRecv(CELLClient* pCLient)
{
	++_recvCount;
}


// 注册时间事件，单位(秒)
unsigned int EasyTcpServer::
add_time_event(CELLTimer::time_callback cb, void *ctx, unsigned int after_sec, int repeat)
{
	return _time_event.register_time_event(cb, ctx, after_sec, repeat);
}

// 更新时间事件，单位(秒)
void EasyTcpServer::
mod_time_event(unsigned int timerid, unsigned int after_sec, int repeat)
{
	_time_event.update_time_event(timerid, after_sec, repeat);
}

// 删除时间事件，单位(秒)
void EasyTcpServer::
del_time_event(unsigned int timerid)
{
	_time_event.unregister_time_event(timerid);
}
